#include <stdio.h>
#include <stdlib.h>

///////// 函数声明 ////////

// 按数值本身的大小, 递增排序.
int origin_compare(int a, int b);
// 按数值距离给定值$N$的距离排序, 距离$N$越近越靠前, $N$由用户输入
int distance_compare(int a, int b);
// 按照数值大小的相反顺序定义, 递减排序.
int reverse_compare(int a, int b);
// 基于选择排序的通用算法
void sort(int *arr, long len, int (*compare)(int, int));
// 要点1: sort函数的函数指针参数compare的类型定义(返回值类型/参数数量与类型)
//         上述三个compare函数是兼容的.

// 用来向distance_compare函数传入比较基准N
int N = 0;

#define ARRAY_LEN 10

int main(void)
{
  int arr[ARRAY_LEN] = {0};
  int i;
  // 读入数组arr
  for (i = 0; i < ARRAY_LEN; i++)
    scanf("%d", &arr[i]);
  // 读入用户指定的排序类型
  int op;
  printf("Choose the comparator:");
  scanf("%d", &op);
  // 定义函数指针comparator
  int (*comparator)(int, int);
  // 根据op的不同, 令函数指针comparator指向不同的函数
  // 要点1: 上述三个函数的函数原型都与该函数指针兼容, 因此可以赋值
  switch (op)
  {
  case 1:
    comparator = origin_compare;
    break;
  case 2:
    printf("Input N:");
    scanf("%d", &N);
    comparator = distance_compare;
    break;
  case 3:
    comparator = reverse_compare;
    break;
  default:
    printf("Unrecognized input\n");
    exit(1);
  }
  // 调用sort函数进行排序
  // 要点2: 将comparator函数指针传入sort函数
  sort(arr, ARRAY_LEN, comparator);
  // 打印排序后的数组内容
  printf("After sort:\n");
  for (i = 0; i < ARRAY_LEN; i++)
  {
    printf("%d ", arr[i]);
  }
  printf("\n");
  return 0;
}

// 按数值本身的大小, 递增排序.
int origin_compare(int a, int b)
{
  if (a < b)
    return -1;
  else
    return 1;
}

// 按数值距离给定值$N$的距离排序, 距离$N$越近越靠前, $N$由用户输入
int distance_compare(int a, int b)
{
  // 计算a距离N的绝对距离
  int distance_a = a - N;
  if (distance_a < 0)
    distance_a = -distance_a;
  int distance_b = b - N;
  if (distance_b < 0)
    distance_b = -distance_b;
  // 根据距离进行比较
  if (distance_a < distance_b)
    return -1;
  else
    return 1;
}

// 按照数值大小的相反顺序定义, 递减排序.
int reverse_compare(int a, int b)
{
  if (a > b)
    return -1;
  else
    return 1;
}

// 基于选择排序的通用算法
void sort(int *arr, long len, int (*compare)(int, int))
{
  long i = 0, j = 0;
  // 对arr[i]到arr[len-1]之间的区间排序
  for (i = 0; i < len - 1; i++)
  {
    // 从区间中选择最小的数组元素
    int current_min_index = i;
    for (j = i + 1; j < len; j++)
    {
      // 调用compare函数对两个数组元素进行比较
      int ret = (*compare)(arr[j], arr[current_min_index]);
      if (ret < 0) // arr[j]应该比arr[current_min_index]排的靠前
      {
        current_min_index = j;
      }
    }
    // swap arr[i] and arr[current_min_index]
    int tmp = arr[current_min_index];
    arr[current_min_index] = arr[i];
    arr[i] = tmp;
  }
}